package com.googlecode.likesql.converter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.googlecode.likesql.expression.AtExp;
import com.googlecode.likesql.utils.StringUtils;

/**
 * This object is to convert {@link AtExp} to a SQL string or template.
 * 
 * @author Johny Huang
 * @since 0.1
 */
public class AtExpConverter implements Converter{

	public String toTemplate(Object obj) {
		AtExp exp=(AtExp)obj;
		Converter cvt=null;
		
		Map values=exp.getValues();
		Object[] keys=values.keySet().toArray();
		String key=null;
		Object value=null;
		String result=exp.getPattern();
		for(int i=keys.length-1;i>=0;i--){
			key=keys[i].toString();
			value=values.get(key);
			cvt=getConverter(value);
			result=StringUtils.replaceFirst(result, AT+key, cvt.toTemplate(value));			
		}
		return result;
	}

	public String toSql(Object obj) {
		AtExp exp=(AtExp)obj;
		Converter cvt=null;
		
		Map values=exp.getValues();
		Object[] keys=values.keySet().toArray();
		String key=null;
		Object value=null;
		String result=exp.getPattern();
		for(int i=keys.length-1;i>=0;i--){
			key=keys[i].toString();
			value=values.get(key);
			cvt=getConverter(value);
			result=StringUtils.replaceFirst(result, AT+key, cvt.toSql(value));			
		}
		return result;
	}
	
	public List toValueList(Object obj) {
		AtExp exp=(AtExp)obj;
		String pattern=exp.getPattern();
		Map values=exp.getValues();
		Object[] keys=values.keySet().toArray();
		
		String key=null;
		AtValue av=null;
		List valueList=new ArrayList();
		int i=0;
		for(i=keys.length-1;i>=0;i--){
			key=keys[i].toString();
			av=new AtValue();
			av.setValue(values.get(key));
			av.setIndex(pattern.indexOf(AT+key));
			valueList.add(av);
		}
		Collections.sort(valueList);
		List resultList=new ArrayList(valueList.size());
		for(i=0;i<valueList.size();i++){
			resultList.add(((AtValue)valueList.get(i)).getValue());
		}
		return resultList;
	}
	
	private final static String AT="@";
	
	private Converter getConverter(Object value){
		ConverterTable table=ConverterTable.getInstance();
		Converter cvt=null;
		if(value==null){
			cvt=table.getDefaultConverter();
		}else{
			cvt=table.getConverter(value.getClass().getName());
		}
		return cvt;
	}

	private final static class AtValue implements Comparable{
		private int index;
		private Object value;
		
		public int getIndex() {
			return index;
		}
		public void setIndex(int index) {
			this.index = index;
		}
		public Object getValue() {
			return value;
		}
		public void setValue(Object value) {
			this.value = value;
		}
		public int compareTo(Object obj) {
			AtValue av=(AtValue)obj;
			if(av==null){
				return -1;
			}else{
				return this.index-av.getIndex();
			}
		}
	}
}
